<template>
	<div style="padding: 14px">
		<el-form>
			<!-- 保持原有表单结构 -->
			<el-row :gutter="24">
				<el-col :span="6">
					<el-form-item label="模型版本">
						<el-select
							v-model="form.currentModel"
							placeholder="请选择"
							:disabled="modelLoading"
							@change="handleModelChange"
						>
							<el-option
								v-for="item in modelList"
								:key="item"
								:label="item"
								:value="item"
							/>
						</el-select>
					</el-form-item>
				</el-col>

				<el-col :span="6">
					<el-form-item :label="`置信度(${form.confidence})`">
						<el-slider
							v-model="form.confidence"
							:min="0.1"
							:max="1"
							:step="0.01"
							style="flex: 1; margin-right: 1rem"
						/>
					</el-form-item>
				</el-col>
			</el-row>
		</el-form>

		<el-card>
			<div class="video-container">
				<div class="inner">
					<span>摄像头</span>
					<video ref="cameraVideo" autoplay muted playsinline></video>
				</div>
				<div class="inner">
					<span>识别结果</span>
					<canvas ref="processedCanvas" class="result-img"></canvas>
				</div>
			</div>
		</el-card>
	</div>
</template>

<script setup lang="ts">
import { ref, onUnmounted, onMounted } from 'vue'
import { ElMessage } from 'element-plus'
import { debounce } from 'lodash-es'
import { modelVersions, changeModel } from '/@/api/yolo_model/hz-system-yolo-model-api'

// const WS_URL = 'ws://192.168.124.11:18765'
const WS_URL = '/ws'
const JPEG_QUALITY = 0.7

// 元素引用
const cameraVideo = ref<HTMLVideoElement>()
const processedCanvas = ref<HTMLCanvasElement>()
const mediaStream = ref<MediaStream>()
const ws = ref<WebSocket>()

// 响应式状态
const form = ref({
	currentModel: '',
	confidence: 0.5
})

const modelList = ref<string[]>([])
const modelLoading = ref(true)
let sending = ref(false)
let animationId: number

// 初始化摄像头
const initCamera = async () => {
	try {
		mediaStream.value = await navigator.mediaDevices.getUserMedia({
			video: { width: 640, height: 480 }
		})

		if (cameraVideo.value) {
			cameraVideo.value.srcObject = mediaStream.value
			cameraVideo.value.play()
		}
	} catch (error) {
		ElMessage.error('摄像头初始化失败')
		console.error('摄像头错误:', error)
	}
}

// WebSocket管理
const connectWebSocket = () => {
	ws.value = new WebSocket(WS_URL)
	ws.value.onopen = () => {
		ElMessage.success('服务器连接成功')
		sending.value = true
		startSendingFrames()
	}

	ws.value.onmessage = (event) => {
		try {
			const data = JSON.parse(event.data)
			console.log(data)
			if (data.type === 'result') {
				drawProcessedImage(data.frame)
			}
		} catch (e) {
			console.error('解析响应失败:', e)
		}
	}

	ws.value.onclose = () => {
		ElMessage.warning('连接断开，尝试重连...')
		setTimeout(connectWebSocket, 3000)
	}

	ws.value.onerror = (error) => {
		console.error('WebSocket错误:', error)
		ElMessage.error('服务器连接错误')
	}
}

// 绘制处理后的图像
const drawProcessedImage = (frameData: string) => {
	if (!processedCanvas.value) return

	const ctx = processedCanvas.value.getContext('2d')
	if (!ctx) return

	const img = new Image()
	img.onload = () => {
		processedCanvas.value!.width = img.width
		processedCanvas.value!.height = img.height
		ctx.drawImage(img, 0, 0)
	}
	img.src = `data:image/jpeg;base64,${frameData}`
}

// 启动帧发送
const startSendingFrames = () => {
	const sendFrame = () => {
		if (!sending.value || !ws.value || ws.value.readyState !== WebSocket.OPEN) return

		const video = cameraVideo.value
		if (!video || video.readyState < 2) return // 检查视频是否就绪

		const canvas = document.createElement('canvas')
		canvas.width = video.videoWidth
		canvas.height = video.videoHeight

		const ctx = canvas.getContext('2d')
		if (!ctx) return

		ctx.drawImage(video, 0, 0, canvas.width, canvas.height)

		const frameData = canvas.toDataURL('image/jpeg', JPEG_QUALITY)

		ws.value.send(JSON.stringify({
			type: 'frame', // 添加类型字段
			frame: frameData,
			model: form.value.currentModel,
			confidence: form.value.confidence,
			image: frameData.split(',')[1]
		}))

		animationId = requestAnimationFrame(sendFrame)
	}

	animationId = requestAnimationFrame(sendFrame)
}

// 模型管理（保持原有逻辑）
const loadModels = async () => {
	try {
		const res = await modelVersions()
		modelList.value = res.data.model_version
		if (modelList.value.length) {
			form.value.currentModel = modelList.value[0]
		}
	} catch (error) {
		ElMessage.error('模型加载失败')
	} finally {
		modelLoading.value = false
	}
}

const handleModelChange = debounce(async (model: string) => {
	try {
		const res = await changeModel(model)
		ElMessage({
			type: res.code === 200 ? 'success' : 'error',
			message: res.msg,
			duration: 2000
		})
	} catch (error) {
		console.error('模型切换失败', error)
	}
}, 500)

// 清理资源
onUnmounted(() => {
	sending.value = false
	if (animationId) cancelAnimationFrame(animationId)
	ws.value?.close()

	mediaStream.value?.getTracks().forEach(track => track.stop())

	if (cameraVideo.value) {
		cameraVideo.value.srcObject = null
		cameraVideo.value.pause()
	}
})

// 初始化
onMounted(async () => {
	await initCamera()
	connectWebSocket()
	loadModels()
})
</script>

<style scoped lang="scss">
.video-container {
	width: 100%;
	display: flex;
	gap: 1rem;
	justify-content: space-between;

	.inner {
		flex: 1;
		position: relative;

		video, .result-img {
			width: 640px;
			height: 480px;
			background: #000;
			border-radius: 4px;
			object-fit: contain;
		}

		span {
			position: absolute;
			top: 8px;
			left: 8px;
			color: white;
			text-shadow: 1px 1px 2px rgba(0,0,0,0.5);
			z-index: 1;
		}
	}
}
</style>
